const database = 'user';
const url = `mongodb://localhost:27017/`;

import {
  Db,
  FilterQuery,
  FindAndModifyWriteOpResultObject,
  MongoClient,
  MongoError,
  OrderedBulkOperation,
} from 'mongodb';
// Connection URI
// Create a new MongoClient
// const client = new MongoClient(`${url}`);

// initModel();
// let client: MongoClient = null;

interface M {
  collection: string;
  [key: string]: any;
}

export class Mod implements M {
  collection: string;
  constructor(_c: string) {
    this.collection = _c;
  }

  async initializeOrderedBulkOp(callback: (v: OrderedBulkOperation) => void) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      const bulkOp = db.collection(this.collection).initializeOrderedBulkOp();
      callback(bulkOp);
      const data = await bulkOp.execute();
      client.close();
      return data;
    } catch (err) {
      console.log(err);
    }
  }

  async aggregate(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .aggregate(arguments[0]);
      client.close();
      return data;
    } catch (err) {}
  }

  async find<T>(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .find<T>(arguments[0], arguments[1])
        .toArray();
      client.close();
      return data;
    } catch (err) {}
  }

  async findOne<T>(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .findOne<T>(arguments[0]);
      client.close();
      return data;
    } catch (err) {}
  }
  async findAll<T>(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .find<T>({}, {})
        .toArray();
      client.close();
      return data;
    } catch (err) {
      console.log(err);
    }
  }

  async insertOne(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      // eslint-disable-next-line prefer-rest-params
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .insertOne(arguments[0], arguments[1]);
      client.close();
      return data;
    } catch (err) {}
  }

  async insertMany(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      // eslint-disable-next-line prefer-rest-params
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .insertMany(arguments[0]);
      client.close();
      return data;
    } catch (err) {}
  }

  async updateOne(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      // eslint-disable-next-line prefer-rest-params
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .updateOne(arguments[0], arguments[1]);
      client.close();
      return data;
    } catch (err) {}
  }
  async updateMany(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      // eslint-disable-next-line prefer-rest-params
      const data = await (<Db>db)
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .updateMany(arguments[0], arguments[1]);
      client.close();
      return data;
    } catch (err) {}
  }
  async deleteOne(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
    } catch (err) {}
    const db = client.db(database);
    const data = await db
      .collection(this.collection)
      // eslint-disable-next-line prefer-rest-params
      .deleteOne(arguments[0]);
    client.close();
    return data;
  }
  async deleteMany(...argvs: any[]) {
    let client;
    try {
      client = await this.initModel();
      const db = client.db(database);
      const data = await db
        .collection(this.collection)
        // eslint-disable-next-line prefer-rest-params
        .deleteMany(arguments[0]);
      client.close();
      return data;
    } catch (err) {}
  }

  findOneAndDelete<T>(
    filter: FilterQuery<any>,
    options?: any,
  ): Promise<FindAndModifyWriteOpResultObject<T>> {
    return new Promise((resolve, reject) => {
      this.initModel().then((client: MongoClient) => {
        const db = client.db(database);
        db.collection<T>(this.collection).findOneAndDelete(
          filter,
          (err: MongoError, data: FindAndModifyWriteOpResultObject<T>) => {
            if (err) {
              reject(err);
            } else {
              resolve(data);
              client.close();
            }
          },
        );
        // const data: FindAndModifyWriteOpResultObject<T> = await db
        //   .collection<T>(this.collection)
        //   // eslint-disable-next-line prefer-rest-params
        //   .findOneAndDelete(filter, options);

        // return data;
      });
      // let client: MongoClient;
      // try {
      //   client = await this.initModel();
      // } catch (err) {
      //   reject(err);
      // }
    });
  }
  initModel(): Promise<MongoClient> {
    return new Promise((resolve, reject) => {
      try {
        const c = new MongoClient(url);
        // Connect the client to the server
        c.connect((err, _client) => {
          if (err) {
            console.log(err);
            console.log(
              '------------------------------------------------------------------------------------------',
            );
            reject(err);
            return;
          }

          resolve(_client);
        });
      } catch (err) {
        // console.log(err);
      }
    });
  }
}

// export function initModel() {
//   return new Promise((resolve, reject) => {
//     try {
//       // Connect the client to the server
//       MongoClient.connect(url, (err, _client) => {
//         client = _client;
//         Mod.db = client.db(database);
//         resolve(null);
//       });
//     } catch (err) {
//       console.log(err);
//     }
//   });
// }

// export function model(collection) {
//   // console.log(client.isConnected());
//   // if (!client.isConnected()) {
//   //   console.log('>>>>>>>>>>>>>');
//   //   initModel().then(() => {
//   //     const db = client.db(database);
//   //     return db.collection(collection);
//   //   });
//   // } else {

//   // }
//   return new Mod(collection);
// }

// export function model() {
//   return new Promise((resolve, reject) => {
//     //连接数据库
//     mongoose.connect(`${url}${database}`, {
//       useNewUrlParser: true,
//     });

//     //监听数据库连接状态
//     mongoose.connection.once('open', () => {
//       console.log('数据库连接成功……');
//       resolve(null);
//     });
//     mongoose.connection.once('close', () => {
//       console.log('数据库断开……');
//     });
//   });
// }
